package com.timebank.timecoin.service.impl;

import com.timebank.common.core.constant.SecurityConstants;
import com.timebank.common.core.constant.StatusConstant;
import com.timebank.common.core.constant.TimeCoinTradeExceptionConstant;
import com.timebank.common.core.constant.TimeCoinTradeStatusConstant;
import com.timebank.common.core.exception.timecoin.TimeCoinTradeException;
import com.timebank.common.core.result.Result;
import com.timebank.common.core.web.pojo.AjaxResult;
import com.timebank.common.security.utils.SecurityUtils;
import com.timebank.system.pojo.SysUser;
import com.timebank.system.service.RemoteUserService;
import com.timebank.timecoin.constant.SortConstant;
import com.timebank.timecoin.mapper.TimeCoinTradeMapper;
import com.timebank.timecoin.pojo.dto.TimeCoinTradeDTO;
import com.timebank.timecoin.pojo.entity.TimeCoinTrade;
import com.timebank.timecoin.pojo.entity.User;
import com.timebank.timecoin.pojo.vo.TimeCoinTradeVO;
import com.timebank.timecoin.service.ContractService;
import com.timebank.timecoin.service.TimeCoinTradeService;
import com.timebank.volunteer.pojo.entity.Volunteer;
import com.timebank.volunteer.pojo.entity.VolunteerAttendList;
import com.timebank.volunteer.pojo.vo.VolunteerAttendListVO;
import com.timebank.volunteer.service.RemoteVolunteerService;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.ContractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * 时间币 接口实现类
 * @author shiliuyinzhen
 */
@Service
@Slf4j
public class TimeCoinTradeServiceImpl implements TimeCoinTradeService{

    @Autowired
    private TimeCoinTradeMapper timeCoinTradeMapper;

    @Autowired
    private ContractService contractService;

    @Autowired
    private RemoteVolunteerService remoteVolunteerService;

    @Autowired
    private RemoteUserService remoteUserService;

    /**
     * 获取时间币支出交易列表
     * @return
     */
    @Override
    public List<TimeCoinTradeVO> getPayTradeByUserId(TimeCoinTradeDTO timeCoinTradeDTO) {
        Long userId = SecurityUtils.getUserId();
        timeCoinTradeDTO.setUserId(userId);
        if (timeCoinTradeDTO.getIsTradeTimeDesc() == null){
            timeCoinTradeDTO.setIsTradeTimeDesc(SortConstant.IS_DESC);
        }
        return timeCoinTradeMapper.getPayTradeByUserId(timeCoinTradeDTO);
    }

    /**
     * 获取时间币收入交易列表
     * @return
     */
    @Override
    public List<TimeCoinTradeVO> getGetTradeByUserId(TimeCoinTradeDTO timeCoinTradeDTO) {
        Long userId = SecurityUtils.getUserId();
        timeCoinTradeDTO.setUserId(userId);
        if (timeCoinTradeDTO.getIsTradeTimeDesc() == null){
            timeCoinTradeDTO.setIsTradeTimeDesc(SortConstant.IS_DESC);
        }
        return timeCoinTradeMapper.getGetTradeByUserId(timeCoinTradeDTO);
    }

    /**
     * 获取时间币所有交易列表
     * @return
     */
    @Override
    public List<TimeCoinTradeVO> getAllTradeByUserId(TimeCoinTradeDTO timeCoinTradeDTO) {
        Long userId = SecurityUtils.getUserId();
        timeCoinTradeDTO.setUserId(userId);
        if (timeCoinTradeDTO.getIsTradeTimeDesc() == null){
            timeCoinTradeDTO.setIsTradeTimeDesc(SortConstant.IS_DESC);
        }
        return timeCoinTradeMapper.getAllTradeByUserId(timeCoinTradeDTO);
    }

    /**
     * 创建时间币交易
     * @param timeCoinTrade
     * @return
     */
    @Override
    public int createTrade(TimeCoinTrade timeCoinTrade) {
        return timeCoinTradeMapper.createTrade(timeCoinTrade);
    }

    /**
     * 修改时间币交易状态
     * @param tradeId
     * @return
     */
    @Override
    @Transactional
    public int updateTradeStatus(Long tradeId) throws ContractException, InterruptedException, TimeoutException {
        //查找时间币交易信息
        TimeCoinTrade timeCoinTrade = timeCoinTradeMapper.getTradeById(tradeId);
        //如果找不到时间币交易
        if (timeCoinTrade == null){
            throw new TimeCoinTradeException(TimeCoinTradeExceptionConstant.TRADE_NOT_FOUND + ",id: " + tradeId);
        }
        //如果交易已经完成
        if (timeCoinTrade.getStatus() == TimeCoinTradeStatusConstant.PAID){
            throw new TimeCoinTradeException(TimeCoinTradeExceptionConstant.TRADE_HAS_PAID);
        }
        //如果交易已经被删除
        if (timeCoinTrade.getDelFlag() == StatusConstant.ENABLE){
            throw new TimeCoinTradeException(TimeCoinTradeExceptionConstant.TRADE_HAS_DELETED);
        }
        //查找用户时间币信息
        User payer = contractService.getUserById(timeCoinTrade.getPayerId());
        User getter = contractService.getUserById(timeCoinTrade.getGetterId());
        //如果支付者余额不足
        if (payer.getTimeCoin() < timeCoinTrade.getTimeCoin()){
            throw new TimeCoinTradeException(TimeCoinTradeExceptionConstant.PAYER_BALANCE_NOT_ENOUGH);
        }
        //修改fabric的用户信息
        payer.setTimeCoin(payer.getTimeCoin() - timeCoinTrade.getTimeCoin());
        getter.setTimeCoin(getter.getTimeCoin() + timeCoinTrade.getTimeCoin());
        contractService.updateUser(payer);
        contractService.updateUser(getter);
        //修改时间币交易信息
        timeCoinTrade.setStatus(TimeCoinTradeStatusConstant.PAID);
        timeCoinTrade.setTradeTime(LocalDateTime.now());
        return timeCoinTradeMapper.updateTrade(timeCoinTrade);
    }

    /**
     * 删除时间币交易
     * @param tradeIds
     * @return
     */
    @Override
    public int deleteTradeByIds(Long[] tradeIds) {
        return timeCoinTradeMapper.deleteTradeByIds(tradeIds);
    }

    /**
     * 根据志愿服务Id和获得者Id删除时间币交易
     * @param volunteerId
     * @param getterId
     * @return
     */
    @Override
    public int deleteTradeByVolunteerIdAndGetterId(Long volunteerId, Long getterId) {
        TimeCoinTrade timeCoinTrade = new TimeCoinTrade();
        timeCoinTrade.setVolunteerId(volunteerId);
        timeCoinTrade.setGetterId(getterId);
        timeCoinTrade.setRemark("取消报名志愿服务");
        return timeCoinTradeMapper.deleteTrade(timeCoinTrade);
    }

    /**
     * 根据志愿服务Id支付时间币
     * @param volunteerId
     * @return
     */
    @Override
    @Transactional
    public AjaxResult payTimeCoinByVolunteerId(Long volunteerId) throws ContractException, InterruptedException, TimeoutException {
        //查询志愿服务
        Result<Volunteer> volunteerResult = remoteVolunteerService.getVolunteerById(volunteerId,SecurityConstants.INNER);
        //查询志愿服务出席名单
        Result<List<VolunteerAttendListVO>> attendListResult = remoteVolunteerService.getVolunteerAttendListByVolunteerId(volunteerId, SecurityConstants.INNER);
        List<VolunteerAttendListVO> attendLists = attendListResult.getData();
        if (attendLists == null || attendLists.size() == 0){
            return AjaxResult.success("支付时间币成功");
        }
        //获取用户ids
        List<Long> userIds = new ArrayList<>();
        for (VolunteerAttendList attendList : attendLists) {
            Long userId = attendList.getUserId();
            userIds.add(userId);
        }
        Volunteer volunteer = volunteerResult.getData();
        Integer timeCoin = volunteer.getTimeCoin();
        //创建时间币交易
        TimeCoinTrade timeCoinTrade = TimeCoinTrade.builder()
                .volunteerId(volunteerId)
                .tradeTime(LocalDateTime.now())
                .status(TimeCoinTradeStatusConstant.PAID)
                .build();
        timeCoinTrade.setRemark("志愿服务结束,自动结算");
        //批量修改时间币交易状态
        timeCoinTradeMapper.batchUpdateTradeByVolunteerId(timeCoinTrade);
        //查找用户信息
        Result<List<SysUser>> result = remoteUserService.getUserByIds(userIds,SecurityConstants.INNER);
        if (result.getData() == null){
            return AjaxResult.error("查找用户信息失败");
        }
        List<SysUser> sysUsers = result.getData();
        //退回剩余时间币
        Integer leftTimeCoin = (volunteer.getVolunteerNum() - attendLists.size()) * volunteer.getTimeCoin();
        List<Long> userIds2 = new ArrayList<>();
        userIds2.add(volunteer.getPublisherId());
        Result<List<SysUser>> publisherResult = remoteUserService.getUserByIds(userIds2, SecurityConstants.INNER);
        List<SysUser> publisherResultData = publisherResult.getData();
        //得到发布人的信息
        SysUser publisher = publisherResultData.get(0);
        //修改时间币
        publisher.setTimeCoin(publisher.getTimeCoin() + leftTimeCoin);
        //将发布人放入users中
        sysUsers.add(publisher);
        //批量更新智能合约信息
        for (SysUser sysUser : sysUsers) {
            //如果不是发布者就加上时间币
            if (sysUser.getUserId() != volunteer.getPublisherId()){
                sysUser.setTimeCoin(sysUser.getTimeCoin() + timeCoin);
            }
            User user = User.builder()
                    .userId(sysUser.getUserId())
                    .userName(sysUser.getUserName())
                    .timeCoin(sysUser.getTimeCoin())
                    .build();
            contractService.updateUser(user);
        }
        //更新出席者时间币
        AjaxResult ajaxResult = remoteUserService.payTimeCoinByIds(userIds,timeCoin, SecurityConstants.INNER);
        if (ajaxResult.isError()){
            return AjaxResult.error("更新fabric账本失败");
        }
        //更新发布者时间币
        SysUser sysUser = new SysUser();
        sysUser.setUserId(volunteer.getPublisherId());
        sysUser.setTimeCoin(publisher.getTimeCoin());
        ajaxResult = remoteUserService.updateUserTimeCoin(sysUser, SecurityConstants.INNER);
        if (ajaxResult.isError()){
            return AjaxResult.error("退回剩余时间币失败");
        }
        //创建退回时间币交易
        TimeCoinTrade timeCoinTrade2 = TimeCoinTrade.builder()
                .volunteerId(volunteerId)
                .payerId(999L)
                .payerName("system")
                .getterId(volunteer.getPublisherId())
                .getterName(volunteer.getCreateBy())
                .timeCoin(leftTimeCoin)
                .status(TimeCoinTradeStatusConstant.PAID)
                .tradeTime(LocalDateTime.now())
                .build();
        timeCoinTrade2.setCreateBy("system");
        timeCoinTrade2.setCreateTime(LocalDateTime.now());
        timeCoinTrade2.setRemark("志愿服务结束，退回剩余时间币");
        return timeCoinTradeMapper.createTrade(timeCoinTrade2) > 0 ? AjaxResult.success("支付成功") : AjaxResult.error("支付失败");
    }

    /**
     * 根据志愿服务Ids批量删除时间币交易
     * @param volunteerIds
     * @return
     */
    @Override
    public int deleteTradeByVolunteerIds(Long[] volunteerIds) {
        return timeCoinTradeMapper.deleteTradeByVolunteerIds(volunteerIds);
    }

    /**
     * 根据用户Ids和志愿服务Id批量删除时间币交易
     * @param userIds
     * @return
     */
    @Override
    public int deleteTradeByUserIdsAndVolunteerId(Long[] userIds, Long volunteerId) {
        return timeCoinTradeMapper.deleteTradeByUserIdsAndVolunteerId(userIds,volunteerId);
    }

    /**
     * 条件查询时间币交易
     * @param timeCoinTrade
     * @return
     */
    @Override
    public List<TimeCoinTradeVO> getTradeByCondition(TimeCoinTrade timeCoinTrade) {
        return timeCoinTradeMapper.getTradeByCondition(timeCoinTrade);
    }
}
